#ifndef OBJECTPOOL_H
#define OBJECTPOOL_H

#include <vector>
#include <stdint.h>

#ifdef _DEBUG
#include <iostream>
#endif

template <class ObjectType>
class ObjectPool
{
public:
	ObjectPool(uint32_t initialPoolSize, uint32_t maxPoolSize) : m_initialPoolSize(initialPoolSize), m_maxPoolSize(maxPoolSize)
#ifdef _DEBUG
		, m_poolHits(0), m_poolMisses(0)
#endif
	{
		for (uint32_t i = 0; i < initialPoolSize; ++i) {
			m_objectsPool.push_back(new ObjectType);
		}
	}
	~ObjectPool() {
		while (this->poolSize()) {
			delete m_objectsPool.back();
			m_objectsPool.pop_back();
		}
#ifdef _DEBUG
		std::cout << "Usage stats for " << this << std::endl;
		std::cout << "poolHits: " << this->poolHits() << endl;
		std::cout << "poolMisses: " << this->poolMisses() << endl;
#endif
	}

	ObjectType *getObject()
	{
		if (this->poolSize()) {
#ifdef _DEBUG
			this->m_poolHits++;
#endif
			ObjectType *ref = m_objectsPool.back();
			m_objectsPool.pop_back();
			return ref;
		} else {
#ifdef _DEBUG
			this->m_poolMisses++;
#endif
			return new ObjectType;
		}
	}

	void releaseObject(ObjectType* object)
	{
		if (this->poolSize() < this->maxPoolSize()) {
			m_objectsPool.push_back(object);
		} else {
			delete object;
		}
	}

	uint32_t poolSize() { return m_objectsPool.size(); }
	uint32_t maxPoolSize() { return m_maxPoolSize; }

#ifdef _DEBUG
	uint32_t poolHits() { return m_poolHits; }
	uint32_t poolMisses() { return m_poolMisses; }
#endif
private:
	/*
	*/
#ifdef _DEBUG
	uint32_t m_poolHits;
	uint32_t m_poolMisses;
#endif
	uint32_t m_initialPoolSize;
	uint32_t m_maxPoolSize;

	std::vector<ObjectType*> m_objectsPool;
};

#endif